/**
 A、特殊类
     1、获取字符串的字节数，扩展string类型方法 byteLength(str)
     2、时间戳的格式转换  formatDate(value,type)
     value 要转换的时间
     type 为0 转为xxxx-xx-xx xx:xx:xx
     type 为1 转为xxxx年xx月xx日xx时xx分xx秒
     3、根据后端传来的对应格式下载对应的文件 downloadStreamFile
     4、暂停numberMillis秒 sleep(numberMillis)
     5、获取url路径上的路径对应参数名的值  getQueryVariable(name)
     http://www.runoob.com/index.php?id=1&image=awesome.jpg
     调用 getQueryVariable("id") 返回 1。
     调用 getQueryVariable("image") 返回 "awesome.jpg"。
     6、登录提示语 早上好、上午好等等  timeFix() 系统温馨提示 showSysTip()
     7、下划线转驼峰 underLine2CamelCase(string)
 B、随机类 数字相关
     随机生成number位包含字母和数字的字符串 randomString(number)
     随机生成数字 randomNumber
     随机生成uuid
     判断输入的数字是否是连续的 isOrderNumeric(numOrStr)
 C、对象、数组相关
     1、对象数组、数组去重 uniqueObjectArray(arr)、unique(arr)
     2、获取两个对象的差异数组    findObjOperate(obj1, obj2)
     3、获取两个对象数组的差异数组  findOperate(list1, list2)
     4、判断对象是否为空 isEmptyObj(obj)
     5、将表格导出成excel exportToExcel(name,id)
     6、判断数组中的数组数据是否有相同数据  judgeArrayRepeat(arr)
     7、过滤对象中为空的属性 filterObj(obj)
     8、清除数组中的某个元素 cleanArray(actual)
     9、深度克隆 deepClone(source)
     10、多余字符用省略号显示 ellipsis(value,len)
 */


import * as XLSX2 from "xlsx";

//获取字符串的字节数，扩展string类型方法
export function byteLength(str) {
    var b = 0,
        l = str.length;  //初始化字节数递加变量并获取字符串参数的字符个数
    if (l > 0) {  //如果存在字符串，则执行计划
        for (var i = 0; i < l; i++) {  //遍历字符串，枚举每个字符
            if (this.charCodeAt(i) > 255) {  //字符编码大于255，说明是双字节字符
                b += 2;  //则累加2个
            } else {
                b++;  //否则递加一次
            }
        }
        return b;  //返回字节数
    } else {
        return 0;  //如果参数为空，则返回0个
    }
}

//时间戳的格式转换
export function formatDate(value, type) {
    let date = new Date(value);
    let y = date.getFullYear();
    let MM = date.getMonth() + 1;
    MM = MM < 10 ? "0" + MM : MM;
    let d = date.getDate();
    d = d < 10 ? "0" + d : d;
    let h = date.getHours();
    h = h < 10 ? "0" + h : h;
    let m = date.getMinutes();
    m = m < 10 ? "0" + m : m;
    let s = date.getSeconds();
    s = s < 10 ? "0" + s : s;
    if (type == 0) {
        return y + "-" + MM + "-" + d + " " + h + ":" + m + ":" + s;
    } else {
        return y + "年" + MM + "月" + d + "日" + h + "时" + m + "分" + s + "秒";
    }
}

//下载文件
export function downloadStreamFile(
    response,
    fileName = 'Unnamed.'
) {
    const contentTypes = [
        {
            fileType: ['xls', 'xlsx'],
            contentType: 'application/vnd.ms-excel;charset=UTF-8'
        },
        {
            fileType: ['ppt'],
            contentType: 'application/vnd.ms-powerpoint;charset=UTF-8'
        },
        {
            fileType: ['pptx'],
            contentType:
                'application/vnd.openxmlformats-officedocument.presentationml.presentation;charset=UTF-8'
        },
        {
            fileType: ['pdf'],
            contentType: 'application/pdf;charset=UTF-8'
        },
        {
            fileType: ['doc'],
            contentType: 'application/msword;charset=UTF-8'
        },
        {
            fileType: ['zip'],
            contentType: 'application/zip;charset=UTF-8'
        }
    ]
    const fileType = fileName.split('.')[1]
    const contentTypeArr = contentTypes.find(v => {
        return v.fileType.includes(fileType)
    })
    const blob = new Blob([response.data], {
        type: contentTypeArr ? contentTypeArr.contentType : 'application/octet-stream;charset=UTF-8'
    })
    const downloadElement = document.createElement('a')
    const href = window.URL.createObjectURL(blob)
    downloadElement.style.display = 'none'
    downloadElement.href = href
    downloadElement.download = fileName
    document.body.appendChild(downloadElement)
    downloadElement.click()
    document.body.removeChild(downloadElement)
    window.URL.revokeObjectURL(href)
}

//暂停 numberMillis 毫秒
export function sleep(numberMillis) {
    var now = new Date();
    var exitTime = now.getTime() + numberMillis;
    while (true) {
        now = new Date();
        if (now.getTime() > exitTime)
            return;
    }
}

//获取url路径上的路径参数的值
/**
 http://www.runoob.com/index.php?id=1&image=awesome.jpg
 调用 getQueryVariable("id") 返回 1。
 调用 getQueryVariable("image") 返回 "awesome.jpg"。
 * @param variable
 * @returns {string|boolean}
 */
export function getQueryVariable(variable) {
    let query = window.location.search.substring(1);
    let vars = query.split("&");
    for (let i = 0; i < vars.length; i++) {
        let pair = vars[i].split("=");
        if (pair[0] == variable) {
            return pair[1];
        }
    }
    return (false);
}

/**
 * 下划线转驼峰
 * @param string
 * @returns {*}
 */
export function underLine2CamelCase(string){
    return string.replace( /_([a-z])/g, function( all, letter ) {
        return letter.toUpperCase();
    });
}

//登录提示语
export function timeFix() {
    const time = new Date()
    const hour = time.getHours()
    return hour < 9 ? '早上好' : (hour <= 11 ? '上午好' : (hour <= 13 ? '中午好' : (hour < 20 ? '下午好' : '晚上好')))
}

//提示语
export function showSysTip() {
    const arr = ['休息一会儿吧', '准备吃什么呢?', '要不要打一把 DOTA', '我猜你可能累了']
    let index = Math.floor((Math.random()*arr.length))
    return arr[index]
}

// 随机生成number位的包含字母和数字的字符串
export function randomString(number) {
    let t = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678",
        a = t.length,
        n = "";
    for (let i = 0; i < number; i++) n += t.charAt(Math.floor(Math.random() * a));
    return n;
}

/**
 * 随机生成数字
 *
 * 示例：生成长度为 12 的随机数：randomNumber(12)
 * 示例：生成 3~23 之间的随机数：randomNumber(3, 23)
 *
 * @param1 最小值 | 长度
 * @param2 最大值
 * @return int 生成后的数字
 */
export function randomNumber() {
    // 生成 最小值 到 最大值 区间的随机数
    const random = (min, max) => {
        return Math.floor(Math.random() * (max - min + 1) + min)
    }
    if (arguments.length === 1) {
        let [length] = arguments
        // 生成指定长度的随机数字，首位一定不是 0
        let nums = [...Array(length).keys()].map((i) => (i > 0 ? random(0, 9) : random(1, 9)))
        return parseInt(nums.join(''))
    } else if (arguments.length >= 2) {
        let [min, max] = arguments
        return random(min, max)
    } else {
        return Number.NaN
    }
}

/**
 * 是否是连续数字
 *
 * @param numOrStr
 * @return
 */
export function isOrderNumeric(numOrStr) {
    let flag = true;
    for (let i = 0; i < numOrStr.length; i++) {
        if (i > 0) {// 判断如123456

            let num = Number(numOrStr.charAt(i) + "");
            let num_ = Number(numOrStr.charAt(i - 1) + "") + 1;
            // console.log(num+' '+num_)
            if (num != num_) {
                flag = false;
                break;
            }
        }
    }
    if (!flag) {
        for (let i = 0; i < numOrStr.length; i++) {
            if (i > 0) {// 判断如654321
                let num = Number(numOrStr.charAt(i) + "");
                let num_ = Number(numOrStr.charAt(i - 1) + "") - 1;
                // console.log(num+' '+num_)
                if (num != num_) {
                    flag = false;
                    break;
                } else {
                    flag = true
                }
            }
        }
    }
    return flag;
}

/**
 * 随机生成uuid
 * @return string 生成的uuid
 */
export function randomUUID() {
    let chats = '0123456789abcdef'
    return randomString(32, chats)
}



//对象数组去重
export function uniqueObjectArray(arr) {
    const res = new Map();
    return arr.filter((arr) => !res.has(arr.id) && res.set(arr.id, 1))
}

//数组去重
export function unique(arr) {
    return Array.from(new Set(arr))
}

/**
 * 找到两个相同结构的对象或相同长度数组的差异内容，并返回包含所有差异的数组  type：1 对象 type：2 数组
 * 注意对象内的值只能是简单类型，复杂类型不考虑
 * @param obj1 原对象
 * @param obj2 可能修改过的对象
 * @returns {{}} 包含所有差异的数组
 */
export function findObjOperate(obj1, obj2, type) {
    const resultObj = {};
    if (type === 1) {
        //遍历obj1的键数组，因为obj1和obj2结构相同，所以不考虑结构上的差异
        Object.keys(obj1).forEach(key => {
            if (obj1[key] !== obj2[key]) {
                //将变化过的属性挂载到返回对象中
                resultObj[key] = obj2[key];
            }
        });
    } else {
        let length = Math.min(obj1.length, obj2.length)
        obj1.forEach((item, index) => {
            if (item !== obj2[index] && index < length) {
                //将变化过的属性挂载到返回对象中
                resultObj[index] = obj2[index];
            }
        })
    }

    return resultObj;
}

/**
 * 找到两个对象数组的差异，并打印从list1到list2的所有变化
 * 注意约定id不能修改
 * @param list1 原数组
 * @param list2 可能修改过的数组
 */
export function findOperate(list1, list2) {
    let modifyList = []
    // console.log(list1)
    // console.log(list2)
    //遍历list2
    list2.forEach((obj2, index) => {
        //根据新索引值在list1中找到对应的对象
        const obj1 = list1[index];
        if (obj1) {
            //比较obj1和obj2的差异
            let objOperateObj = {};
            Object.keys(obj1).forEach(key => {
                if (obj1[key] !== obj2[key]) {
                    //将变化过的属性挂载到返回对象中
                    objOperateObj = obj2
                }
            });
            // console.log(objOperateObj)
            //如果返回的对象为空对象，表示没有差异
            if (!isEmptyObj(objOperateObj)) {
                modifyList.push(objOperateObj)
                // console.log('modify', obj1.id,objOperateObj);
            }
        }
    });
    return modifyList
}

/**
 * 判断对象是否为空
 * @param obj 对象
 * @returns {boolean} 为空返回true，不为空返回false
 */
export function isEmptyObj(obj) {
    //如果对象的键数组的长度是0，表示为空对象
    return Object.keys(obj).length === 0;
}

/**
 * 针对某一对象的某一个属性进行归类
 * 如[{ name:'a1',age:30},{ name:'a1',age:31},{ name:'a1',age:32},{ name:'a2',age:30},{ name:'a2',age:31}] 对name进行归类
 * 变为[{
 *     [{
 *         { name:'a1',age:30},{ name:'a1',age:31},{ name:'a1',age:32}
 *     }]
 * }
 */
export function groupDataByKey(data, key) {
    let temp = []
    let groupData = []
    data.forEach((dataItem) => {
        // console.log(dataItem)
        let idx = temp.indexOf(dataItem[key])
        // console.log(idx)
        if (idx === -1) {
            // console.log(dataItem[key])
            temp.push(dataItem[key])
            groupData.push({
                [key]: dataItem[key],
                groupData: []
            })
            groupData[groupData.length - 1].groupData.push(dataItem)
        } else {
            groupData[idx].groupData.push(dataItem)
        }
    })
    // console.log(groupData)
    return groupData
}

//将表格导出成excel  npm install --save xlsx
export function exportToExcel(name, id) {
    /* generate workbook object from table */
    var xlsxParam = {raw: true}

    let exportTable = document.getElementById(id);
    let worksheet = XLSX2.utils.table_to_sheet(exportTable, xlsxParam);


    let workbook = XLSX2.utils.book_new();
    XLSX2.utils.book_append_sheet(workbook, worksheet, 'sheet');
    let wscols = [    // 每列不同宽度px
        {wpx: 180},
        {wpx: 100},
        {wpx: 120},
    ];
    workbook["Sheets"]['sheet']["!cols"] = wscols;

    // 导出的内容只做解析，不进行格式转换
    // var wb = XLSX.utils.table_to_book(exportTable, xlsxParam)
    //
    // /* get binary string as output */
    // var wbout = XLSX.write(workbook, { bookType: 'xlsx', bookSST: true, type: 'array' })

    // console.log(new Array(10).fill({ wpx: 110 }))

    try {
        XLSX2.writeFile(workbook, `${name}.xlsx`);
        // FileSaver.saveAs(new Blob([wbout], { type: 'application/octet-stream' }), `${name}.xlsx`)
    } catch (e) {
        if (typeof console !== 'undefined') {
            console.log(e, workbook)
        }
    }
    return false
}

//判断数组中的数组数据是否有相同数据
export function judgeArrayRepeat(arr) {
    console.log(arr)
    let flag = false
    for (let [xIndex, xItem] of arr.entries()) {
        for (let [yIndex, yItem] of arr.entries()) {
            // console.log(yItem)
            let intersectionSet = []
            if (xIndex != yIndex) {
                intersectionSet = xItem.filter(x => yItem.indexOf(x) > -1)
                console.log(intersectionSet)
                if(intersectionSet.length>0){
                    flag = true
                    break
                }
            }
        }
        if (flag) {
            break
        }
    }
    return flag
}

//过滤对象中为空的属性
export function filterObj(obj) {
    if (!(typeof obj == 'object')) {
        return;
    }

    for ( var key in obj) {
        // eslint-disable-next-line no-prototype-builtins
        if (obj.hasOwnProperty(key)
            && (obj[key] == null || obj[key] == undefined || obj[key] === '')) {
            delete obj[key];
        }
    }
    return obj;
}

//清除数组中的某个元素
export function cleanArray(actual) {
    const newArray = []
    for (let i = 0; i < actual.length; i++) {
        if (actual[i]) {
            newArray.push(actual[i])
        }
    }
    return newArray
}

//深度克隆 lodash's _.cloneDeep
export function deepClone(source) {
    if (!source && typeof source !== 'object') {
        throw new Error('error arguments', 'deepClone')
    }
    const targetObj = source.constructor === Array ? [] : {}
    Object.keys(source).forEach(keys => {
        if (source[keys] && typeof source[keys] === 'object') {
            targetObj[keys] = deepClone(source[keys])
        } else {
            targetObj[keys] = source[keys]
        }
    })
    return targetObj
}

//多余字符用省略号显示
export function ellipsis(value, len) {
    if (!value) return ''
    if (value.length > len) {
        return value.slice(0, len) + '...'
    }
    return value
}
